using System;
using System.Collections.Generic;
using NUnit.Framework;
using Tycho.Parser.Peg;

namespace Tycho.Parser.Tests.Peg {
    [TestFixture]
    public class DynamicParsingFeature {
        private DynamicChoiceProduction Expression;

        [SetUp]
        public void SetUp () {
            Expression = new DynamicChoiceProduction ();
        }

        [Test]
        public void ShouldInsertNewExpressionSyntaxMidParse () {
            var terminal = new ChoiceProduction (StatementDelimiterProduction.CreateTerminal (), IdentifierProduction.CreateTerminal ());
            var expressionTerminal = new ChoiceProduction (Expression, terminal);
            var statements = new NonTerminal ("statements",
                                              new DelimitedRule (new NamedRule ("expressions", expressionTerminal),
                                                                 new LiteralRule(StatementDelimiterProduction.CreateTerminal ())), new[] {"expressions"});

            var dynamicGrammar = CreateExpressionContext ();

            string source =
@"nop
print print nop
print macro number
print number nop";

            ITerm result = statements.ParseTerm (source, null, dynamicGrammar);

            Assert.IsNotNull (result);
        }

        private IDynamicGrammar CreateExpressionContext () {
            var nop = new NonTerminal ("nop", new LiteralRule (IdentifierKeywordProduction.CreateTerminal ("nop")));
            var expressionRule = new NamedRule ("expression", Expression);
            var print = new NonTerminal ("print",
                                            new SequenceRule (new LiteralRule (IdentifierKeywordProduction.CreateTerminal ("print")),
                                                              expressionRule));
            print.ResultTransform = r => {
                                        Console.WriteLine (r.Term);
                                        return r;
                                    };

            var macro = new NonTerminal ("macro",
                                         new SequenceRule (new KeywordRule ("macro"),
                                                           new NamedRule ("name", IdentifierProduction.CreateTerminal ())));
            macro.ResultTransform = InstallMacro;

            var dynamicGrammar = new LazyDynamicGrammar ();
            dynamicGrammar.AddDynamicChoice (Expression, new [] {nop, print, macro});

            return dynamicGrammar;
        }

        private ParseResult InstallMacro (ParseResult result) {
            string name = ((IdentifierTerm) ((CompositeTerm) result.Term).SubTerms["name"]).Name;

            result.Context = result.Context.Clone ();

            var newMacro = new NonTerminal (name,
                                            new SequenceRule (new KeywordRule (name),
                                                              new NamedRule ("expression", Expression)));
            result.Context.DynamicGrammar.InsertChoiceLast (Expression, newMacro);

            return result;
        }
    }
}